////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 
// 
// This file is part of the Microsoft .NET Micro Framework Porting Kit Code Samples and is unsupported. 
// Copyright (C) Microsoft Corporation. All rights reserved. Use of this sample source code is subject to 
// the terms of the Microsoft license agreement under which you licensed this sample source code. 
// 
// THIS SAMPLE CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, 
// INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// 
// 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <tinyhal.h>
//#include "AT91_TIMER.h"


//--//

//--//

#if defined(ADS_LINKER_BUG__NOT_ALL_UNUSED_VARIABLES_ARE_REMOVED)
#pragma arm section zidata = "g_AT91_TIMER_Driver"
#endif

AT91_TIMER_Driver g_AT91_TIMER_Driver;

#if defined(ADS_LINKER_BUG__NOT_ALL_UNUSED_VARIABLES_ARE_REMOVED)
#pragma arm section zidata
#endif

//--//

BOOL AT91_TIMER_Driver::Initialize( UINT32 Timer, BOOL FreeRunning, UINT32 ClkSource, HAL_CALLBACK_FPN ISR, void* ISR_Param )
{
    ASSERT(Timer < AT91_MAX_TIMER);

    GLOBAL_LOCK(irq);

    if(g_AT91_TIMER_Driver.m_descriptors[Timer].configured == TRUE) return FALSE;

    g_AT91_TIMER_Driver.m_descriptors[Timer].isr = ISR;
    g_AT91_TIMER_Driver.m_descriptors[Timer].arg = ISR_Param;

    //--//

    if(ISR)
    {
        if(!CPU_INTC_ActivateInterrupt( AT91C_ID_TC0+Timer, ISR_TIMER, (void*)Timer )) return FALSE;
    }

    {
        struct AT91_TC *pTc = (AT91_TC *) (AT91C_BASE_TC0 + Timer*0x40);

        // First, enable the clock of the TIMER
        // Todo clock API - PMC
        *((volatile int*)(AT91C_BASE_PMC + 0x010)) = (1 << (AT91C_ID_TC0+Timer));

        // Disable the clock and the interrupts
        pTc->TC_CCR = AT91_TC::TC_CLKDIS;
        pTc->TC_IDR = 0xFFFFFFFF;

        // Clear status bit
        (void) pTc->TC_SR;

        // Set the Mode of the Timer Counter
        if( FreeRunning == TRUE )
            pTc->TC_CMR = (ClkSource);
        else
            pTc->TC_CMR = (AT91_TC::TC_CPCTRG | ClkSource);
            
        // Enable Interrupt (Compare RC)
        pTc->TC_IER = AT91_TC::TC_CPCS;

        // Enable the clock
        pTc->TC_CCR = (AT91_TC::TC_CLKEN | AT91_TC::TC_SWTRG);
    }

    g_AT91_TIMER_Driver.m_descriptors[Timer].configured = TRUE;

    return TRUE;
}

BOOL AT91_TIMER_Driver::Uninitialize( UINT32 Timer )
{
    // Get Timer pointer
    struct AT91_TC *pTc = (AT91_TC *)(AT91C_BASE_TC0 + Timer*0x40);

    // Disable the clock
    pTc->TC_CCR = AT91_TC::TC_CLKDIS;

    // Clear Irq Status
    (void) pTc->TC_SR;

    // Disable All Irq
    pTc->TC_IDR = 0xFFFFFFFF;

    // First, enable the clock of the TIMER
    // Todo clock API - PMC
    *((volatile int*)(AT91C_BASE_PMC + 0x014)) = (1 << (AT91C_ID_TC0+Timer));

    g_AT91_TIMER_Driver.m_descriptors[Timer].configured = FALSE;

    return TRUE;
}

void AT91_TIMER_Driver::ISR_TIMER( void* param )
{
    UINT32 Timer = (UINT32)param;

    ASSERT(Timer < AT91_MAX_TIMER);

    // Execute the ISR for the Timer
    (g_AT91_TIMER_Driver.m_descriptors[Timer].isr)(g_AT91_TIMER_Driver.m_descriptors[Timer].arg);
}

#pragma arm section code = "SectionForFlashOperations"


#pragma arm section code

